package net.kong.sns.rest.client.rest;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import net.kong.org.springframework.http.HttpHeaders;
import net.kong.org.springframework.http.HttpInputMessage;
import net.kong.org.springframework.http.HttpOutputMessage;
import net.kong.org.springframework.http.HttpStatus;
import net.kong.org.springframework.http.MediaType;
import net.kong.org.springframework.http.client.ClientHttpResponse;
import net.kong.org.springframework.http.converter.AbstractHttpMessageConverter;
import net.kong.org.springframework.util.FileCopyUtils;

/**
 * @author <a href="mailto:lanhuai@gmail.com">Ning Yubin</a>
 * @version $Id: HttpJsonResponseContentConverter.java,v 1.2 2009/07/29 09:05:38 yongkun Exp $
 */
public class HttpJsonResponseContentConverter extends AbstractHttpMessageConverter<HttpResponseContent> {
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    private final List<Charset> availableCharsets;

    public HttpJsonResponseContentConverter() {
        super(new MediaType("application", "json", DEFAULT_CHARSET), new MediaType("text", "plain", DEFAULT_CHARSET));
        this.availableCharsets = new ArrayList<Charset>(Charset.availableCharsets().values());
    }

    public boolean supports(Class<? extends HttpResponseContent> clazz) {
        return HttpResponseContent.class.equals(clazz);
    }

    public HttpResponseContent read(Class<HttpResponseContent> clazz, HttpInputMessage inputMessage) throws IOException {
        MediaType contentType = inputMessage.getHeaders().getContentType();
        Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : DEFAULT_CHARSET;
        String body = FileCopyUtils.copyToString(new InputStreamReader(inputMessage.getBody(), charset));
        HttpHeaders headers = inputMessage.getHeaders();
        if (inputMessage instanceof ClientHttpResponse) {
            ClientHttpResponse clientHttpResponse = (ClientHttpResponse) inputMessage;
            HttpStatus httpStatus = clientHttpResponse.getStatusCode();
            return new HttpResponseContent(headers, body, httpStatus);
        }
        return new HttpResponseContent(headers, body);
    }

    @Override
    protected Long getContentLength(HttpResponseContent s) {
        Charset charset = getContentType(s).getCharSet();
        if (charset != null) {
            try {
                return (long) s.getBody().getBytes(charset.name()).length;
            }
            catch (UnsupportedEncodingException ex) {
                // should not occur
                throw new InternalError(ex.getMessage());
            }
        }
        else {
            return null;
        }
    }

    @Override
    protected void writeToInternal(HttpResponseContent s, HttpOutputMessage outputMessage) throws IOException {
        outputMessage.getHeaders().setAcceptCharset(getAcceptedCharsets());
        MediaType contentType = getContentType(s);
        Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : DEFAULT_CHARSET;
        FileCopyUtils.copy(s.getBody(), new OutputStreamWriter(outputMessage.getBody(), charset));
    }

    /**
     * Return the list of supported {@link Charset}.
     * <p>By default, returns {@link Charset#availableCharsets()}. Can be overridden in subclasses.
     * @return the list of accepted charsets
     */
    protected List<Charset> getAcceptedCharsets() {
        return this.availableCharsets;
    }
}
